package com.dreamana.components
{
	import com.dreamana.ui.BaseComponent;
	import com.dreamana.ui.SkinGraphics;
	
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	[Event(name="select", type="flash.events.Event")]
	
	public class List extends BaseComponent
	{
		protected var _selectedIndex:int = -1;
		protected var _items:Array = [];
		protected var _cells:Array = [];
		protected var _cellWidth:int;
		protected var _cellHeight:int;
		protected var _cellClass:Class = ListCell;
		protected var _back:Shape;
		protected var _backColor:int = -1;
		protected var _backTexture:BitmapData;
		protected var _backScale9Grid:Rectangle;
		protected var _border:Shape;
		protected var _borderColor:int = 0x0;
		protected var _container:Sprite;
		protected var _mask:Shape;
		protected var _vscrollbar:VSlider;
		
		
		public function List(w:int, h:int)
		{
			_width = w;
			_height = h;
			
			//default cell size
			_cellWidth = w;
			_cellHeight = ListCell.defaultFormat.size +8; 
			
			this.init();
		}
		
		override protected function addChildren():void
		{
			_back = new Shape();
			this.addChild(_back);
			
			_container = new Sprite();
			this.addChild(_container);
			
			_mask = new Shape();
			this.addChild(_mask);
			
			_container.mask = _mask;
			
			_vscrollbar = new VSlider(20, _height);//default scrollbar width
			_vscrollbar.x = _width - _vscrollbar.width;
			this.addChild(_vscrollbar);
			
			_border = new Shape();
			this.addChild(_border);
			
			_vscrollbar.addEventListener(Event.SCROLL, onVScrollbarScroll);
		}
		
		protected function makeList():void
		{
			var i:int, num:int;
			var cell:ListCell;
			
			//remove all old cells
			i = _cells.length;
			while(i--) {
				cell = _cells[i];
				
				cell.removeEventListener(MouseEvent.CLICK, onCellClick);
				_container.removeChild(cell);
				disposeCell(cell);
			}
			_cells.length = 0;
			
			//add new cells
			num = _items.length;
			for(i=0; i < num; i++) {
				var item:Object = _items[i];
				var labelText:String = item.hasOwnProperty("label") ? item["label"] : "";
				
				cell = getCell();
				cell.reset(_cellWidth, _cellHeight, labelText);
				cell.x = 0;
				cell.y = _cellHeight * i;
				cell.addEventListener(MouseEvent.CLICK, onCellClick);
				_container.addChild(cell);
				
				if(i == _selectedIndex) cell.selected = true;
				
				_cells[_cells.length] = cell;
			}
		}
		
		//--- Object Pool ----		
		
		protected var _cellPool:Array = [];
		
		protected function getCell():ListCell {
			return _cellPool.pop() || new _cellClass();
		}
		
		protected function disposeCell(cell:ListCell):void {
			if(cell) _cellPool.push(cell);
		}
		
		//--- PUBLIC METHODS ---
				
		override public function draw():void
		{
			var g:Graphics;
			
			//mask resize
			g = _mask.graphics;
			g.clear();
			g.beginFill(0x0);
			g.drawRect(0, 0, _width, _height);
			g.endFill();
			
			//background
			g = _back.graphics;
			g.clear();
			if(_backTexture) {
				if(_backScale9Grid) SkinGraphics.fill9Grid(g, _backTexture, _width, _height, _backScale9Grid, false);
				else SkinGraphics.fillRect(g, _backTexture, _width, _height);
			}
			else if(_backColor >= 0) {
				SkinGraphics.drawBlank(g, _width, _height, _backColor);
			}
			else {
				SkinGraphics.drawWireFrame(g, _width, _height);
			}
			
			//scrollbar
			_vscrollbar.setSize(_vscrollbar.width, _height);
			_vscrollbar.x = _width - _vscrollbar.width;
			_vscrollbar.visible = (_cellHeight * _items.length > _height);
			_vscrollbar.setDraggerSize(_vscrollbar.dragger.width, Math.max(Math.min(_height*2 - _cellHeight*_items.length, _height), _vscrollbar.width));
			
			//cells
			_cellWidth = _width;
			makeList();
			
			//border
			g = _border.graphics;
			g.clear();
			if(_borderColor >= 0) {
				g.lineStyle(0, _borderColor);
				g.drawRect(0, 0, _width -1, _height -1);
			}
		}
		
		override public function setStyle(style:String, value:Object):void
		{
			super.setStyle(style, value);
			
			switch(style) {
				case "cell-renderer":
					this.setCellRenderer(value as Class);
					break;
				case "cell-width":
					_cellWidth = value as Number;
					invalidate();
					break;
				case "cell-height":
					_cellHeight = value as Number;
					invalidate();
					break;
				case "border-color":
					_borderColor = value as Number;
					invalidate();
					break;
				case "background-color":
					_backColor = value as Number;
					invalidate();
					break;
				case "background-image":
					_backTexture = value as BitmapData;
					invalidate();
					break;
				case "background-9grid":
					_backScale9Grid = value as Rectangle;
					invalidate();
			}
		}
		
		public function setItems(listData:Array):void
		{
			_items = listData;
			
			_selectedIndex = -1;
			
			invalidate();
		}
		
		public function setCellRenderer(value:Class):void
		{
			_cellClass = value;
			
			//remove cells and clear pool
			var i:int = _cells.length;
			while(i--) {
				var cell:ListCell = _cells[i];
				cell.removeEventListener(MouseEvent.CLICK, onCellClick);
				this.removeChild(cell);
			}
			_cells.length = 0;
			_cellPool.length = 0;
			
			invalidate();
		}
		
		public function select(index:int):void
		{
			var cell:ListCell;
			
			//unselect last one
			if(_selectedIndex >= 0) {
				cell = _cells[_selectedIndex];
				if(cell) cell.selected = false;
			}
			
			//update selected index
			_selectedIndex = index;
			
			if(index >= 0 && index < _cells.length) {
				//select this one
				cell = _cells[index];
				if(cell) cell.selected = true;
				
				this.dispatchEvent(new Event(Event.SELECT));
			}
			else if(index == -1) {
				//when deselected...
				this.dispatchEvent(new Event(Event.SELECT));
			}
		}
		
		public function scrollToSelection():void
		{
			if(_cellHeight * _items.length <= _height) return;
			
			//scrolls the list to make the selected item appear in the view.
			var top:int = 0;
			var bottom:int = _height - _cellHeight;
			if(_selectedIndex >= 0)
			{
				var cellY:Number = _cellHeight * _selectedIndex;
				var py:Number = _container.y + cellY;
				if(py < top) _container.y = top - cellY;
				else if(py > bottom) _container.y = bottom - cellY;
			}
			else {
				_container.y = top;
			}
			
			//update vscrollbar position
			_vscrollbar.percent = _container.y / (_height - _cellHeight * _items.length);
		}
		
		//--- EVENT HANDLERS ---
		
		protected function onCellClick(event:MouseEvent):void
		{
			var target:ListCell = event.currentTarget as ListCell;
			if(deselectable && target.selected) select(-1);
			else select( _cells.indexOf(target) );
		}		
		
		protected function onVScrollbarScroll(event:Event):void
		{
			_container.y = Math.round( Math.min(_height - _container.height, 0) * _vscrollbar.percent );
		}
		
		//--- GETTER/SETTERS ---
		public function get selectedIndex():int { return _selectedIndex; }
		public function set selectedIndex(value:int):void { 
			select(value);
			scrollToSelection();
		}
		
		public function get selectedItem():Object {	return _items[_selectedIndex]; }
		public function get items():Array { return _items; }
		public function get cellContainer():Sprite { return _container; }
		public function get vscrollbar():VSlider { return _vscrollbar; }
		public function get cellWidth():int { return _cellWidth; }
		public function get cellHeight():int { return _cellHeight; }
		
		public var deselectable:Boolean = false;
	}
}